home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / WINDOWS / GOLFIERY.ZIP / C / TOOLTIPS / TOOLTIPS.C next >
Encoding:
C/C++ Source or Header  |  1995-04-03  |  12.1 KB  |  407 lines

  1. /*** tooltips.c ***
  2.    Balloon help (ToolTips) in C. Just a demo of what's possible.
  3.  
  4.    An example of FlyByHintHelpFromWindow & FlyByHintHelpFromClass.
  5.    In C you need to do some subclassing/superclassing.
  6.  
  7.    The balloon functions are used in DlgWinWndProc & ChildSubProc
  8.  
  9.    No copyrights claimed. Donated to the public domain.
  10.  
  11.    Author:
  12.       Alfons Hoogervorst
  13.  
  14.    E-mail:
  15.       2:500/121.6252 (Fido)
  16.       a.hoogervorst@dosgg.nl (Internet)
  17.  
  18.    BBS:
  19.       DOSBoss West aka The C Programmers Board. Syshost Alex Stienstra
  20.       31-20-6124530, V32b,V42b,CM,XA, 8 data bits, no parity, 1 stop bitt
  21.  
  22.    Necessary files:
  23.       tooltips.c     - This file
  24.       tooltips.rh    - Resource header file
  25.       golfiery.h     - All definitions for golfiery
  26.       tooltips.rc    - resource script
  27.       golfiery.dll   - golfiery DLL
  28.       golfiery.lib   - Import library
  29.  
  30.    Last revised:
  31.       March/April, 1995
  32.  
  33.    Remarks:
  34.       Use smart callbacks.
  35.  
  36.    Special shoutouts:
  37.       Harry Gijzen - Look at the procs RegisterNewFlyByHintClass,
  38.          NewFlyByHintWndProc (Superclassing) & SubclassAllchilds,
  39.          ChildSubProc (Subclassing)
  40.       Rob de Voer
  41.       Erik Baas
  42.       Fabio Cereda Cordeiro
  43. *******************/
  44.  
  45. #include <windows.h>
  46. #include "golfiery.h"
  47. #include "tooltips.rh"
  48.  
  49. /*** Classnames & property strings ***/
  50. #define DLGCLASSNAME          "Ahii_DlgFlyByHintInC"
  51. #define BALLOONDLL            "GOLFIERY.DLL"
  52.  
  53. /*** Class name for new balloon window ***/
  54. #define NEWFLYBYHINTCLASSNAME   "nAhii_FlyByHint"
  55.  
  56. /*** Prototypes ***/
  57. #ifdef __cplusplus
  58. extern "C" {
  59. #endif
  60.  
  61. /*** DLL functions ***/
  62. BOOL RegisterDlgWin (void);
  63. BOOL RegisterNewFlyByHintClass (void);
  64.  
  65. LRESULT CALLBACK _export DlgWinWndProc(HWND, UINT, WPARAM, LPARAM);
  66. LRESULT CALLBACK _export NewFlyByHintWndProc(HWND, UINT, WPARAM, LPARAM);
  67. LRESULT CALLBACK _export ChildSubProc(HWND, UINT, WPARAM, LPARAM);
  68.  
  69. void DlgWin_OnCommand(HWND, WORD);
  70. void DlgWin_OnPaint(HWND, LPRECT);
  71.  
  72. void SubclassAllChilds(HWND);
  73. #ifdef __cplusplus
  74. }
  75. #endif
  76.  
  77.  
  78. /*** Some global variables ***/
  79. static HINSTANCE  _hInst;
  80. static HWND       _hwndMain;
  81. static BOOL       _fOtherClass = FALSE;
  82. static BOOL       _fToolTip = TRUE;
  83. static WNDPROC    _lpfnOldProc;
  84. char              painttext[] = "Area managed by dialog";
  85. int               painttextlen;
  86.  
  87.  
  88. int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  89.     LPSTR lpszCmdLine, int nCmdShow)
  90. {
  91.    MSG message;
  92.  
  93.    _hInst = hInstance;
  94.  
  95.    hPrevInstance = hPrevInstance;
  96.    lpszCmdLine = lpszCmdLine;
  97.  
  98.    // First time initialization
  99.    if ( !RegisterDlgWin() || !RegisterNewFlyByHintClass() )
  100.     return -1;
  101.  
  102.    // Calculate text length
  103.    painttextlen = lstrlen(painttext);
  104.    _hwndMain = CreateDialogParam(_hInst, MAKEINTRESOURCE(IDD_MAINDIALOG),
  105.       NULL, NULL, NULL);
  106.    if ( !_hwndMain ) return -1;
  107.  
  108.    // Windows passes a CmdShow parameter to the program.
  109.    ShowWindow(_hwndMain, nCmdShow);
  110.    UpdateWindow(_hwndMain);
  111.  
  112.    // Run Message Loop
  113.    while ( GetMessage(&message, 0, 0, 0) )
  114.    {
  115.       // If main window will contain modeless dialogs we must call
  116.       //   this function. Otherwise TABBING not possible.
  117.       if ( IsDialogMessage(_hwndMain, &message) ) continue;
  118.  
  119.       // Otherwise pass to normal message processing
  120.       TranslateMessage(&message);
  121.       DispatchMessage(&message);
  122.    }
  123.    return message.wParam;
  124. }
  125.  
  126.  
  127. /*** RegisterDlgWin ***
  128.    Registers our main window. Ofcourse a tribute to Charles Petzold.
  129. ***********************/
  130. BOOL RegisterDlgWin(void)
  131. {
  132.    WNDCLASS wndclass;
  133.  
  134.    wndclass.style = CS_HREDRAW | CS_VREDRAW;
  135.    wndclass.lpfnWndProc = (WNDPROC) DlgWinWndProc;
  136.  
  137.    /*** Extra window and class bytes ***/
  138.    wndclass.cbClsExtra = 0;
  139.    wndclass.cbWndExtra = DLGWINDOWEXTRA; // Necessary.
  140.  
  141.    wndclass.hInstance = _hInst;
  142.    wndclass.hIcon = LoadIcon(_hInst, MAKEINTRESOURCE(IDI_MAINDIALOG));
  143.    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  144.    wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  145.  
  146.    wndclass.lpszMenuName = NULL;
  147.    wndclass.lpszClassName = DLGCLASSNAME;
  148.  
  149.    /*** Try to register window ***/
  150.    return (RegisterClass(&wndclass));
  151. }
  152.  
  153.  
  154. /*** RegisterNewFlyByHintClass ***
  155.    Assorted techniques :-). First retrieves the HINSTANCE of Golfiery.
  156.    Next we get the info about the balloon window class, and use the
  157.    returned info for our new superclassed balloon. Actually the
  158.    superclassed balloon has just another color. So it does nothing
  159.    special at all. (We need to provide a window procedure!)
  160. ********************************/
  161. BOOL RegisterNewFlyByHintClass(void)
  162. {
  163.    WNDCLASS    wndclass;
  164.    HINSTANCE   hInstGolfiery;
  165.  
  166.    /*** Get instance handle of the balloon dll ***/
  167.    hInstGolfiery = LoadLibrary(BALLOONDLL);
  168.    FreeLibrary(hInstGolfiery);
  169.  
  170.    if ( !GetClassInfo(hInstGolfiery, FLYBYHINTCLASSNAME, &wndclass) )
  171.       return 0;
  172.  
  173.    /*** This class isn't global, clear bit ***/
  174.    wndclass.style &= ~CS_GLOBALCLASS;
  175.  
  176.    /*** New class will be valid for this instance only ***/
  177.    _lpfnOldProc = wndclass.lpfnWndProc;
  178.    wndclass.lpfnWndProc = NewFlyByHintWndProc;
  179.    wndclass.hInstance = _hInst;
  180.  
  181.    /*** Greenish color. Was searching for a strawberry color.
  182.         couldn't find an appropriate color :-( ***/
  183.    wndclass.hbrBackground = CreateSolidBrush(RGB(202, 243, 203)) ;
  184.    wndclass.lpszMenuName = NULL;
  185.    wndclass.lpszClassName = NEWFLYBYHINTCLASSNAME;
  186.  
  187.    return (RegisterClass(&wndclass));
  188. }
  189.  
  190.  
  191. /*** DlgWinWndProc ***
  192.    Handles all main window messages.  The dialog also manages a hot spot
  193.    area for tooltip info. Take a look at it's WM_MOUSEMOVE handler.
  194. **********************/
  195. LRESULT CALLBACK _export DlgWinWndProc(HWND hDlg, UINT uMsg, WPARAM wParam,
  196.   LPARAM lParam)
  197. {
  198.    static   BOOL  fSubclassed;
  199.    static   RECT  rcManagedArea;
  200.    BOOL        fCallDefault = TRUE;
  201.    LRESULT  lResult = 0;        // 0 means handled
  202.  
  203.    switch ( uMsg )
  204.     {
  205.  
  206.       /*** In show window we subclass all controls that need the
  207.            special tooltips. ***/
  208.       case WM_SHOWWINDOW:
  209.          CheckDlgButton(hDlg, IDC_TOGGLEHELP, (UINT)_fToolTip);
  210.          CheckDlgButton(hDlg, IDC_OTHERCLASS, (UINT)_fOtherClass);
  211.  
  212.          /*** Not subclassed yet ***/
  213.          if ( !fSubclassed ) {
  214.             GetClientRect(GetDlgItem(hDlg, 800), &rcManagedArea);
  215.             MapWindowPoints(GetDlgItem(hDlg, 800), hDlg,
  216.                (LPPOINT)&rcManagedArea, 2);
  217.  
  218.             /*** Destroy the "managed area window". We just need it for
  219.                  client coords ***/
  220.             DestroyWindow(GetDlgItem(hDlg, 800));
  221.             SubclassAllChilds(hDlg);
  222.             fSubclassed++;
  223.          }
  224.          break;
  225.  
  226.       case WM_PAINT:
  227.          DlgWin_OnPaint(hDlg, &rcManagedArea);
  228.          break;
  229.  
  230.       case WM_MOUSEMOVE:
  231.          if ( _fToolTip )
  232.             if (PtInRect(&rcManagedArea, *((LPPOINT)&lParam))) {
  233.                RECT  rcWindow;
  234.  
  235.                rcWindow = rcManagedArea;
  236.                MapWindowPoints(hDlg, 0, (LPPOINT)&rcWindow, 2);
  237.  
  238.                if ( _fOtherClass ) FlyByHintFromClass(_hInst,
  239.                   NEWFLYBYHINTCLASSNAME, _hwndMain, &rcWindow, painttext);
  240.                else FlyByHint(_hwndMain, &rcWindow, painttext);
  241.             }
  242.          break;
  243.  
  244.       case WM_COMMAND:         // Dialog comands
  245.          DlgWin_OnCommand(hDlg, wParam);
  246.          break;            //   fCallDefault = TRUE
  247.  
  248.       case WM_DESTROY:
  249.          PostQuitMessage(0);
  250.          fCallDefault = FALSE;
  251.          break;
  252.     }
  253.  
  254.    // if fCallDefault is TRUE we will call DefWindowProc (for default
  255.    //   window behaviour
  256.    if ( fCallDefault ) lResult = DefWindowProc(hDlg, uMsg, wParam, lParam);
  257.    return lResult;
  258. }
  259.  
  260.  
  261. /*** NewFlyByHintWndProc ***
  262.    The superclass' window procedure
  263. **************************/
  264. LRESULT CALLBACK _export NewFlyByHintWndProc(HWND hFlyByHint, UINT uMsg,
  265.    WPARAM wp, LPARAM lp)
  266. {
  267.    static HFONT   hFont;
  268.  
  269.    switch ( uMsg ) {
  270.       case WM_CREATE:
  271.          {
  272.             LOGFONT  logfont;
  273.             int      c;
  274.  
  275.             /*** Clear out logfont struct. I didn't want to include
  276.                  yet another header file ***/
  277.             for (c = 0; c < sizeof logfont; c++) ((LPBYTE)&logfont)[c] = 0;
  278.             logfont.lfItalic = 1;
  279.             lstrcpy(logfont.lfFaceName, "Arial");
  280.             hFont = CreateFontIndirect(&logfont);
  281.          }
  282.          break;
  283.  
  284.       /*** WM_GETFONT returns font handle. It's not necessary to pass it to
  285.            default handler. Nor is it necessary to check if hFont is
  286.            valid.
  287.  
  288.            WM_GETFONT is sent by the WM_PAINT handling code.
  289.            if hFont == 0 the WM_PAINT code  uses
  290.            GetStockObject(ANSI_VAR_FONT) ***/
  291.       case WM_GETFONT:
  292.          return (LRESULT)hFont;
  293.  
  294.       case WM_DESTROY:
  295.          if (hFont) DeleteObject(hFont);
  296.          break;
  297.    }
  298.  
  299.    /*** Call old procedure for old behaviour ***/
  300.    return CallWindowProc(_lpfnOldProc, hFlyByHint, uMsg, wp, lp);
  301. }
  302.  
  303.  
  304. /*** DlgWin_OnCommand ***
  305.    Handler of control notification messages
  306. *************************/
  307. void DlgWin_OnCommand(HWND hDialog, WORD wId)
  308. {
  309.    switch ( wId ) {
  310.       case IDC_TOGGLEHELP:
  311.          _fToolTip = IsDlgButtonChecked(hDialog, IDC_TOGGLEHELP);
  312.          break;
  313.       case IDC_OTHERCLASS:
  314.          _fOtherClass = IsDlgButtonChecked(hDialog, IDC_OTHERCLASS);
  315.          break;
  316.    }
  317. }
  318.  
  319.  
  320. /*** DlgWin_OnPaint ***
  321.    Paints the dialog. Yes. It actually paints on the dialog.
  322. ***********************/
  323. void DlgWin_OnPaint(HWND hDlg, LPRECT rcManagedArea)
  324. {
  325.    PAINTSTRUCT ps;
  326.    DWORD       dwExt;
  327.  
  328.    BeginPaint(hDlg, &ps);
  329.    Rectangle(ps.hdc, rcManagedArea->left, rcManagedArea->top,
  330.       rcManagedArea->right, rcManagedArea->bottom);
  331.  
  332.    SelectObject(ps.hdc, GetStockObject(SYSTEM_FONT));
  333.    SetBkMode(ps.hdc, OPAQUE);
  334.    dwExt = GetTextExtent(ps.hdc, painttext, painttextlen);
  335.  
  336.    SetTextAlign(ps.hdc, TA_LEFT | TA_BASELINE);
  337.    TextOut(ps.hdc, 4 * GetSystemMetrics(SM_CXBORDER) + rcManagedArea->left,
  338.       rcManagedArea->top + ((int)HIWORD(dwExt)/2), painttext,
  339.       painttextlen);
  340.  
  341.    EndPaint(hDlg, &ps);
  342. }
  343.  
  344.  
  345. /*** SubclassAllChilds ***
  346.    Subclasses all childs. I don't store the old pointer. I just
  347.    make a call to the class' old proc (*not* the window's old proc)
  348. **************************/
  349. void SubclassAllChilds(HWND hDialog)
  350. {
  351.    HWND  hwndChild = GetWindow(hDialog, GW_CHILD);
  352.  
  353.    while ( hwndChild ) {
  354.       if ( GetWindowWord(hwndChild, GWW_ID) < 200 )
  355.          SetWindowLong(hwndChild, GWL_WNDPROC, (LONG)ChildSubProc);
  356.       hwndChild = GetWindow(hwndChild, GW_HWNDNEXT);
  357.    }
  358. }
  359.  
  360.  
  361.  
  362. /*** ChildSubProc ***
  363.    Almost all messages to controls are routed to this window procedure
  364. *********************/
  365. LRESULT CALLBACK _export ChildSubProc(HWND hChild, UINT uMsg, WPARAM wp,
  366.    LPARAM lp)
  367. {
  368.    /*** Get "old" procedure ***/
  369.    WNDPROC  lpfnOldProc = (WNDPROC)GetClassLong(hChild, GCL_WNDPROC);
  370.  
  371.    /*** First let old procedure handle the message ***/
  372.    LRESULT  lResult = CallWindowProc(lpfnOldProc, hChild, uMsg, wp, lp);
  373.  
  374.    int      id = GetWindowWord(hChild, GWW_ID);
  375.  
  376.    /*** Statics don't do mouse moves, we have to "enable" them. Instead
  377.         returning HTTRANSPARENT we return HTCLIENT. It's a little
  378.         simplistic, if the static has a border we should also test if the
  379.         mouse is in the non-client area ***/
  380.    if ( (id == IDC_STATICPOINT) &&
  381.         (uMsg == WM_NCHITTEST) &&
  382.         (lResult == HTTRANSPARENT) )
  383.       return HTCLIENT;
  384.  
  385.    /*** Just need to trap the WM_MOUSEMOVE ***/
  386.    if ( uMsg == WM_MOUSEMOVE )
  387.       if ( _fToolTip ) {
  388.          RECT  rcWindow;
  389.          char  buf[50];
  390.  
  391.          buf[0] = 0;
  392.  
  393.          /*** Get screen coordinates of control ***/
  394.          GetWindowRect(hChild, &rcWindow);
  395.  
  396.          /*** Get the string associated with this control ***/
  397.          LoadString(_hInst, IDS_TEXT_HELP + id, (LPSTR)&buf, sizeof buf);
  398.          if (_fOtherClass)
  399.             FlyByHintFromClass(_hInst, NEWFLYBYHINTCLASSNAME, _hwndMain, &rcWindow, buf);
  400.          else
  401.             FlyByHintFromWindow(_hwndMain, hChild, buf);
  402.       }
  403.  
  404.    return lResult;
  405. }
  406.  
  407.